package org.oslims.client.presenter;

import java.util.List;
import java.util.Set;

import org.oslims.client.AsyncCall;
import org.oslims.client.MainEventBus;
import org.oslims.client.service.DepartmentServiceAsync;
import org.oslims.client.uicomponents.SortableHeader;
import org.oslims.client.uicomponents.WidgetUtils;
import org.oslims.client.uicomponents.editbox.EditDepartmentBox;
import org.oslims.client.view.DepartmentEditorView;
import org.oslims.client.view.impl.DepartmentEditorViewImpl;
import org.oslims.domain.Department;

import com.google.gwt.cell.client.ButtonCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.validation.client.InvalidConstraint;
import com.google.gwt.validation.client.interfaces.IValidator;
import com.google.gwt.view.client.ListView;
import com.google.gwt.view.client.Range;
import com.google.gwt.view.client.ListView.Delegate;
import com.mvp4g.client.annotation.InjectService;
import com.mvp4g.client.annotation.Presenter;
import com.mvp4g.client.presenter.BasePresenter;

@Presenter(view = DepartmentEditorViewImpl.class)
public class DepartmentPresenter extends BasePresenter<DepartmentEditorView, MainEventBus> {

	private DepartmentServiceAsync departmentService;
	private IValidator<Department> departmentValidator;

	private String currentSortProperty = "name";
	private Boolean currentSortDesc = false;

	public DepartmentPresenter() {
		departmentValidator = GWT.create(Department.class);
	}

	public void onShowDepartmentManagement(DockLayoutPanel mainWidget) {

		WidgetUtils.removeCenterWidget(mainWidget);
		mainWidget.add(view.getViewWidget());

		refreshData();

	}

	@InjectService
	public void setDepartmentService(DepartmentServiceAsync departmentService) {
		this.departmentService = departmentService;
	}

	@Override
	// Set up the required click handlers
	public void bind() {
		bindEditBox();
		addColumns();
		setDelegate();
	}

	private void refreshData() {
		departmentService.getDepartmentCount(new AsyncCall<Integer>() {

			@Override
			protected void onFailureE(Throwable caught) {
				eventBus.error(caught.getMessage());
			}

			@Override
			protected void onSuccessE(Integer result) {
				view.getTable().setDataSize(result, true);

				if (result < view.getDefaultPageSize()) {
					view.getPager().setVisible(false);
					view.getTable().setPageSize(result);
				}
				view.getTable().refresh();
			}
		});
	}

	private void setDelegate() {
		view.getTable().setDelegate(new Delegate<Department>() {

			@Override
			public void onRangeChanged(ListView<Department> listView) {

				final Range r = listView.getRange();

				departmentService.getAllDepartments(r.getStart(), r.getLength(), currentSortProperty, currentSortDesc, new AsyncCall<List<Department>>() {

					@Override
					protected void onFailureE(Throwable caught) {
						eventBus.error(caught.getMessage());
					}

					@Override
					protected void onSuccessE(List<Department> result) {
						view.getTable().setData(r.getStart(), r.getLength(), result);
						view.getTable().redraw();
					}
				});
			}
		});
	}

	private void addColumns() {
		final SortableHeader nameHeader = new SortableHeader("Name", "name");
		nameHeader.setSorted(true);
		nameHeader.setUpdater(new ValueUpdater<String>() {

			@Override
			public void update(String value) {
				nameHeader.toggleReverseSort();
				currentSortProperty = nameHeader.getPropertyName();
				currentSortDesc = nameHeader.getReverseSort();
				view.getTable().refresh();
				view.getTable().refreshHeaders();
			}
		});

		view.getTable().addColumn(new TextColumn<Department>() {

			@Override
			public String getValue(Department object) {
				return object.getName();
			}
		}, nameHeader);

		view.getTable().addColumn(new TextColumn<Department>() {

			@Override
			public String getValue(Department object) {
				return object.getAbbreviation();
			}
		}, "Abbr.");

		view.getTable().addColumn(new TextColumn<Department>() {

			@Override
			public String getValue(Department object) {
				return object.getLabStaff().size() + "";
			}
		}, "Staff Count");

		Column<Department, String> editColumn = new Column<Department, String>(new ButtonCell()) {

			@Override
			public String getValue(Department object) {
				return "Edit";
			}
		};

		editColumn.setFieldUpdater(new FieldUpdater<Department, String>() {

			@Override
			public void update(int index, Department object, String value) {

				view.getEditDepartmentBox().showEdit(object);
			}
		});

		view.getTable().addColumn(editColumn);
	}

	private void bindEditBox() {
		view.getNewDepartmentButton().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				view.getEditDepartmentBox().showNew();
			}
		});

		view.getEditDepartmentBox().getCancelButton().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				view.getEditDepartmentBox().hide();
			}

		});

		view.getEditDepartmentBox().getSaveButton().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				if (view.confirmEdit("Do you want to save your changes?"))
					saveDepartment();
			}
		});
	}

	public void saveDepartment() {

		EditDepartmentBox editBox = view.getEditDepartmentBox();
		Department tempDepartment = editBox.getDepartment();

		if (tempDepartment == null)
			tempDepartment = new Department();

		tempDepartment.setName(editBox.getName().getValue());
		tempDepartment.setAbbreviation(editBox.getUnit().getValue());

		Set<InvalidConstraint<Department>> departmentErrors = departmentValidator.validate(tempDepartment);

		if (departmentErrors.size() > 0) {
			for (InvalidConstraint<Department> ic : departmentErrors) {
				editBox.showError(ic.getItemName(), ic.getMessage());
			}
			return;
		}

		departmentService.editDepartment(tempDepartment, new AsyncCall<Void>() {

			@Override
			public void onSuccessE(Void result) {
				refreshData();
				view.getEditDepartmentBox().hide();
			}

			@Override
			public void onFailureE(Throwable error) {
				eventBus.error(error.getMessage());
			}
		});

	}
}
